package info.motteke.mybws.poi;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * セルの座標を表すクラスです。
 * 
 * @author YWak
 */
public class CellIndex {

    /** インデックスに使用される文字 */
    private static final String INDEX_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    /** インデックスのパターン */
    private static final Pattern PATTERN = Pattern.compile("([A-Za-z]+)([0-9]+)");

    /**
     * 文字列をインデックスに変換します。
     * 
     * @param index
     *            Excel上のセルの位置を表す文字列
     * @return セルの位置
     */
    public static CellIndex toIndex(String index) {
        Matcher matcher = PATTERN.matcher(index);

        if (!matcher.matches()) {
            throw new IllegalArgumentException("illegal index format : " + index);
        }

        String column = matcher.group(1);
        String row = matcher.group(2);

        int rowIndex = Integer.parseInt(row) - 1;
        int columnIndex = toIntegerIndex(column) - 1;

        return new CellIndex(rowIndex, columnIndex);
    }

    /**
     * インデックスを文字列化します。
     * 
     * @param index
     *            インデックス
     * @return indexの文字列表現
     */
    private static String toString(int index) {
        StringBuilder buf = new StringBuilder();

        while (true) {
            index--;
            buf.append(INDEX_CHARS.charAt(index % INDEX_CHARS.length()));
            index /= INDEX_CHARS.length();

            if (index == 0) {
                break;
            }
        }

        return buf.reverse().toString();
    }

    /**
     * 文字列で表現されたインデックスを数値化します。
     * 
     * @param index
     *            インデックス
     * @return indexが表す位置
     */
    private static int toIntegerIndex(String index) {

        index = index.toUpperCase();
        int n = 0;

        for (int i = 0, length = index.length(); i < length; i++) {
            n *= INDEX_CHARS.length();
            n++;

            char c = index.charAt(i);
            int idx = INDEX_CHARS.indexOf(c);

            assert idx != -1;

            n += idx;
        }

        return n;
    }

    /** 行の位置 */
    private final int rowIndex;

    /** 列の位置 */
    private final int columnIndex;

    public CellIndex(int rowIndex, int columnIndex) {
        if (rowIndex < 0) {
            throw new IllegalArgumentException("index must be positive but " + rowIndex);
        }

        if (columnIndex < 0) {
            throw new IllegalArgumentException("index must be positive but " + columnIndex);
        }

        this.rowIndex = rowIndex;
        this.columnIndex = columnIndex;
    }

    /**
     * 行の位置を取得します。
     * 
     * @return 行の位置
     */
    public int getRowIndex() {
        return rowIndex;
    }

    /**
     * 列の位置を取得します。
     * 
     * @return 列の位置
     */
    public int getColumnIndex() {
        return columnIndex;
    }

    @Override
    public String toString() {
        return toString(getColumnIndex() + 1) + (getRowIndex() + 1);
    }
}
